﻿using BJoin.Application.BObject;
using BJoin.Application.Entity;
using BJoin.DapperExtension.Postgresql.TypeHandler;
using Dapper;
using DapperExtensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BJoin.Application.IRepository
{
    public abstract class BaseRepository<T, TKey,TExt> where T : Entity<TKey,TExt> where TExt:BObjExt
    {
        /// <summary>
        /// DI Container Provider
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }

        protected BaseRepository(IServiceProvider provider)
        {
            ServiceProvider = provider;
            SqlMapper.AddTypeHandler(typeof(TExt), new JsonTypeHandler<TExt>());
        }
        #region 异步
        public virtual async Task<long> CountAsync(object predicate = null)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.CountAsync<T>(predicate);
        }
        public virtual async Task<T> GetAsync(TKey id)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.GetAsync<T>(id);
        }
        public virtual async Task<IEnumerable<T>> GetListAsync(object predicate = null, string[] sorts = null)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.GetListAsync<T>(predicate, RepositoryHelper.OrderByToSort<T>(sorts));
        }
        public virtual async Task<Page<T>> GetListPagingAsync(int pageNumber, int recordsPerPage, object predicate = null, string[] sorts = null)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.GetPagesAsync<T>(pageNumber, recordsPerPage, predicate, RepositoryHelper.OrderByToSort<T>(sorts));
        }

        public virtual async Task<IEnumerable<T>> GetListSetAsync(int firstResult, int maxResults, object predicate = null, string[] sorts = null)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.GetSetAsync<T>(predicate, RepositoryHelper.OrderByToSort<T>(sorts), firstResult, maxResults);
        }

        public virtual async Task<IEnumerable<dynamic>> GetDynamicAsync(string sql)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.GetDynamicAsync(sql);
        }
        public virtual async Task<TKey> InsertAsync(T entity )
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.InsertAsync(entity);
        }
        public virtual async Task<IEnumerable<TKey>> InsertManyAsync(IEnumerable<T> entities)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            await database.InsertAsync(entities);
            return entities.Select(e => e.Id);
        }
        public virtual async Task<bool> UpdateAsync(T entity, object predicate)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.UpdateAsync<T>(entity,predicate);
        }
        public virtual async Task<bool> UpdateSetAsync(T entity, object predicate)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.UpdateSetAsync<T>(entity, predicate);
        }
        public virtual async Task<bool> DeleteAsync(TKey id)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.DeleteAsync<T>(new { Id = id });
        }

        public virtual async Task<bool> DeleteAsync(object predicate = null)
        {
            RepositoryHelper.ObjectNotNull(predicate);
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.DeleteAsync<T>(predicate);
        }
        public virtual async Task<bool> DeleteAsync(string ids)
        {
            using IServiceScope scope = ServiceProvider.CreateScope();
            var database = scope.ServiceProvider.GetService<IDatabase>();
            return await database.DeleteAsync<T>(new { Id = ids.Split(',') });
        }
        #endregion
    }
}
